from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
from django.shortcuts import render, redirect

import os
import json
import time, datetime, random

from docker import Client
from utilities import *

from docker_engine.models import Node, Application, Task, Container, Image, ContainerResourceConsumption



# Set up docker client
docker_client = Client(base_url='unix://var/run/docker.sock')



def dashboard_view(request):
    return redirect("/docker/task/index")










# Start for Application Controller
def task_index_view(request):
    response_data = {}
    response_data["page_title"] = "Dashboad"
    response_data["module_name"] = "Overview"
    response_data["content_name"] = ""

    response_data["tasks"] = Task.objects.all()

    return render(request, "docker_engine/task/index.html", response_data)



def task_detail_view(request, task_name):
    response_data = {}
    response_data["page_title"] = "Task"
    response_data["module_name"] = "Detail"
    response_data["content_name"] = task_name

    current_task = Task.objects.get(name=task_name)
    response_data["task"] = current_task
    response_data["containers"] = current_task.container_set.all()

    return render(request, "docker_engine/task/detail.html", response_data)



alpha = 1
def task_ajax_stats(request, task_name, stats_type):
    response_data = {}
    if stats_type == "cpu":
        response_data["cpu"] = 20 + random.random()*10 + alpha
    elif stats_type == "memory":
        response_data["memory"] = 50 + alpha
    elif stats_type == "io":
        response_data["io"] = {}
        response_data["io"]["read"] = 20.3 + alpha
        response_data["io"]["write"] = 15.6 + alpha
    elif stats_type == "network":
        response_data["network"] = {}
        response_data["network"]["receive"] = 5.3 + alpha
        response_data["network"]["send"] = 2.7 + alpha

    """
    task = Task.objects.get(name=task_name)
    containers = task.container_set.all()
    response_data = {}

    for con in containers:
        statistics = docker_client.stats(container_name, stream=False)
        if stats_type == "cpu":
            container_cpu_usage = statistics["cpu_stats"]["cpu_usage"]["total_usage"] - \
                        statistics["precpu_stats"]["cpu_usage"]["total_usage"]
            system_cpu_usage = statistics["cpu_stats"]["system_cpu_usage"] - \
                                statistics["precpu_stats"]["system_cpu_usage"]
            response_data["cpu"] = container_cpu_usage * 100.0 / system_cpu_usage
        elif stats_type == "memory":
            container_memory_usage = statistics["memory_stats"]["usage"]
            system_memory_usage = statistics["memory_stats"]["limit"]
            response_data["memory"] = container_memory_usage * 100.0 / system_memory_usage
        elif stats_type == "io":
            container_read_bytes = statistics["blkio_stats"]["io_service_bytes_recursive"][0]["value"]
            container_write_bytes = statistics["blkio_stats"]["io_service_bytes_recursive"][1]["value"]
            response_data["io"] = {}
            response_data["io"]["read"] = container_read_bytes / 1024.0 / 1024.0
            response_data["io"]["write"] = container_write_bytes / 1024.0 / 1024.0
        elif stats_type == "network":
            if "eth0" in statistics["networks"]:
                container_receive_bytes = statistics["networks"]["eth0"]["rx_bytes"]
                container_send_bytes = statistics["networks"]["eth0"]["tx_bytes"]
                response_data["network"] = {}
                response_data["network"]["receive"] = container_receive_bytes / 1024.0 / 1024.0
                response_data["network"]["send"] = container_send_bytes / 1024.0 / 1024.0
    """
    return JsonResponse(response_data)



def task_new_view(request):
    response_data = {}
    response_data["page_title"] = "Task"
    response_data["module_name"] = "Task"
    response_data["content_name"] = "Start Task"

    response_data["applications"] = Application.objects.all()

    return render(request, "docker_engine/task/new.html", response_data)



def task_create_view(request):
    name = request.POST.get("task_name")
    application_name = request.POST.get("application_name")
    if (not name) or (not application_name):
        return HttpResponse("Invalid Parameters")

    # temporary
    application=Application.objects.get(name=application_name)

    new_task = Task.objects.create(
        name=name,
        application=application,
        node=Node.objects.all()[3]
    )

    
    """
    definition_file = handle_static_file(application.definition_file)
    for line in definition_file:
        if not line[0].isspace():
            container_name = line.strip[:-1]
            Container.objects.create(
                name=container_name,
                task=new_task,
                image=image_name
            )
    """
    Container.objects.create(
        name="redisserver_redis_1",
        task=new_task,
        image=Image.objects.get(name="redis"),
        status="R"
    )
    Container.objects.create(
        name="redisserver_web_1",
        task=new_task,
        image=Image.objects.get(name="ubuntu"),
        status="R"
    )
    

    #os.command("cd applications/" + application_name + " && "+ "docker-compose up -d")

    return redirect("/docker/task/index")



def task_delete_view(request, task_name):
    Task.objects.get(name=task_name).delete()

    return redirect("/docker/task/index")










# Start for Application Controller
def node_index_view(request):
    response_data = {}
    response_data["page_title"] = "Computing Node"
    response_data["module_name"] = "Node"
    response_data["content_name"] = "Index"

    response_data["nodes"] = Node.objects.all()

    return render(request, "docker_engine/node/index.html", response_data)



def node_detail_view(request, node_name):
    response_data = {}
    response_data["page_title"] = "Computing Node"
    response_data["module_name"] = "Node"
    response_data["content_name"] = node_name

    response_data["node"] = Node.objects.get(name=node_name)

    return render(request, "docker_engine/node/detail.html", response_data)



def node_new_view(request):
    response_data = {}
    response_data["page_title"] = "Computing Nodes"
    response_data["module_name"] = "Node"
    response_data["content_name"] = "New"

    return render(request, "docker_engine/node/new.html", response_data)



def node_create_view(request):
    name = request.POST.get("node_name")
    ip_address = request.POST.get("ip_address")
    role = request.POST.get("role")
    if (not name) or (not ip_address) or (not role):
        return HttpResponse("Invalid Parameters")

    cpu = int(request.POST.get("cpu"))
    memory = float(request.POST.get("memory"))
    io_read = float(request.POST.get("io_read"))
    io_write = float(request.POST.get("io_write"))
    net_send = float(request.POST.get("net_send"))
    net_receive = float(request.POST.get("net_receive"))

    Node.objects.create(
        name=name,
        ip_address=ip_address,
        role=role,
        cpu=cpu,
        memory=memory,
        io_read=io_read,
        io_write=io_write,
        net_send=net_send,
        net_receive=net_receive
    )

    return redirect("/docker/node/index")



def node_update_view(request):
    name = request.POST.get("node_name")
    ip_address = request.POST.get("ip_address")
    role = request.POST.get("role")
    if (not name) or (not ip_address) or (not role):
        return HttpResponse("Invalid Parameters")

    cpu = int(request.POST.get("cpu"))
    memory = float(request.POST.get("memory"))
    io_read = float(request.POST.get("io_read"))
    io_write = float(request.POST.get("io_write"))
    net_send = float(request.POST.get("net_send"))
    net_receive = float(request.POST.get("net_receive"))

    Node.objects.filter(name=name).update(
        name=name,
        ip_address=ip_address,
        role=role,
        cpu=cpu,
        memory=memory,
        io_read=io_read,
        io_write=io_write,
        net_send=net_send,
        net_receive=net_receive
    )

    return redirect("/docker/node/index")



def node_delete_view(request, node_name):
    Node.objects.get(name=node_name).delete()
    
    return redirect("/docker/node/index")










# Start for Application Controller
def application_index_view(request):
    response_data = {}
    response_data["page_title"] = "Application"
    response_data["module_name"] = "Application"
    response_data["content_name"] = "Index"

    response_data["applications"] = Application.objects.all()
    
    return render(request, "docker_engine/application/index.html", response_data)



def application_definition_view(request, application_name):
    application = Application.objects.get(name=application_name)
    definition_file = handle_static_file(application.definition_file)

    return HttpResponse(definition_file)



def application_detail_view(request, application_name):
    response_data = {}
    response_data["page_title"] = "Application"
    response_data["module_name"] = "Application"
    response_data["content_name"] = application_name

    application = Application.objects.get(name=application_name)
    response_data["application"] = application
    response_data["definition_file"] = handle_static_file(application.definition_file)
    
    return render(request, "docker_engine/application/detail.html", response_data)



def application_new_view(request):
    response_data = {}
    response_data["page_title"] = "Application"
    response_data["module_name"] = "Application"
    response_data["content_name"] = "Definition"

    return render(request, "docker_engine/application/new.html", response_data)



def application_create_view(request):
    name = request.POST.get("application_name")
    definition_file = request.FILES["definition_file"]
    if (not name) or (not definition_file):
        return HttpResponse("Invalid Parameters")

    cpu_limit = int(request.POST.get("cpu_limit"))
    memory_limit = float(request.POST.get("memory_limit"))
    io_read_limit = float(request.POST.get("io_read_limit"))
    io_write_limit = float(request.POST.get("io_write_limit"))
    net_send_limit = float(request.POST.get("net_send_limit"))
    net_receive_limit = float(request.POST.get("net_receive_limit"))

    definition_file_path = handle_application_creation(name, definition_file)

    Application.objects.create(
        name=name,
        definition_file=definition_file_path, 
        cpu_limit=cpu_limit,
        memory_limit=memory_limit,
        io_read_limit=io_read_limit,
        io_write_limit=io_write_limit,
        net_send_limit=net_send_limit,
        net_receive_limit=net_receive_limit
    )

    return redirect("/docker/application/index")



def application_update_view(request):
    name = request.POST.get("application_name")

    cpu_limit = int(request.POST.get("cpu_limit"))
    memory_limit = float(request.POST.get("memory_limit"))
    io_read_limit = float(request.POST.get("io_read_limit"))
    io_write_limit = float(request.POST.get("io_write_limit"))
    net_send_limit = float(request.POST.get("net_send_limit"))
    net_receive_limit = float(request.POST.get("net_receive_limit"))

    Application.objects.create(
        name=name,
        definition_file=definition_file_path, 
        cpu_limit=cpu_limit,
        memory_limit=memory_limit,
        io_read_limit=io_read_limit,
        io_write_limit=io_write_limit,
        net_send_limit=net_send_limit,
        net_receive_limit=net_receive_limit
    )

    return redirect("/docker/application/index")



def application_delete_view(request, application_name):
    Application.objects.get(name=application_name).delete()

    return redirect("/docker/application/index")










# Start for Container Controller
def container_index_view(request):
    response_data = {}
    response_data["page_title"] = "Container"
    response_data["module_name"] = "Container"
    response_data["content_name"] = "Index"

    response_data["containers"] = Container.objects.all()

    return render(request, "docker_engine/container/index.html", response_data)



def container_new_view(request):
    response_data = {}
    response_data["page_title"] = "Contianer"
    response_data["module_name"] = "Container"
    response_data["content_name"] = "Definition"
    
    response_data["images"] = Image.objects.all()

    return render(request, "docker_engine/container/new.html", response_data)



def container_create_view(request):
    name = request.POST.get("container_name")
    image = request.POST.get("container_image")
    command = request.POST.get("container_command")
    volumes = request.POST.get("container_volumes")
    ports = request.POST.get("container_ports")

    if (not name) or (not image) or (not command):
        return HttpResponse("Invalid Parameters")

    """# create and start container
    new_container = docker_client.create_container(name=name, image=image,
        command=command, volumes=eval(volumes), ports=eval(ports))
    docker_client.start(new_container)"""

    # save to database
    task = Task.objects.get(name="idle")
    Container.objects.create(task=task, name=name, image=Image.objects.get(name=image),
        command=command, volumes=volumes, ports=ports, status="R")

    return redirect("/docker/container/index")



def container_ajax_start(request, container_name):
    docker_client.start(container_name)

    response_data = {}

    return JsonResponse(response_data)



def container_ajax_stop(request, container_name):
    docker_client.stop(container_name)

    response_data = {}

    return JsonResponse(response_data)



def container_delete_view(request, container_name):
    docker_client.remove_container(container_name, force=True)
    Container.objects.get(name=container_name).delete()

    return redirect("/docker/container/index")



def container_detail_view(request, container_name):
    response_data = {}
    response_data["page_title"] = "Container"
    response_data["module_name"] = "Container"
    response_data["content_name"] = container_name

    container_info = docker_client.inspect_container(container=container_name)
    response_data["container"] = {}
    response_data["container"]["id"] = container_info["Id"][:32]
    response_data["container"]["name"] = container_info["Name"][1:]
    response_data["container"]["command"] = container_info["Config"]["Cmd"][0]
    response_data["container"]["volumes"] = container_info["Config"]["Volumes"]
    response_data["container"]["address"] = container_info["NetworkSettings"]["IPAddress"]
    response_data["container"]["ports"] = container_info["NetworkSettings"]["Ports"]

    return render(request, "docker_engine/container/detail.html", response_data)



def container_ajax_stats(request, container_name, stats_type):
    statistics = docker_client.stats(container_name, stream=False)
    
    response_data = {}
    if stats_type == "cpu":
        container_cpu_usage = statistics["cpu_stats"]["cpu_usage"]["total_usage"] - \
                    statistics["precpu_stats"]["cpu_usage"]["total_usage"]
        system_cpu_usage = statistics["cpu_stats"]["system_cpu_usage"] - \
                            statistics["precpu_stats"]["system_cpu_usage"]
        response_data["cpu"] = container_cpu_usage * 100.0 / system_cpu_usage
    elif stats_type == "memory":
        container_memory_usage = statistics["memory_stats"]["usage"]
        system_memory_usage = statistics["memory_stats"]["limit"]
        response_data["memory"] = container_memory_usage * 100.0 / system_memory_usage
    elif stats_type == "io":
        container_read_bytes = statistics["blkio_stats"]["io_service_bytes_recursive"][0]["value"]
        container_write_bytes = statistics["blkio_stats"]["io_service_bytes_recursive"][1]["value"]
        response_data["io"] = {}
        response_data["io"]["read"] = container_read_bytes / 1024.0 / 1024.0
        response_data["io"]["write"] = container_write_bytes / 1024.0 / 1024.0
    elif stats_type == "network":
        if "eth0" in statistics["networks"]:
            container_receive_bytes = statistics["networks"]["eth0"]["rx_bytes"]
            container_send_bytes = statistics["networks"]["eth0"]["tx_bytes"]
            response_data["network"] = {}
            response_data["network"]["receive"] = container_receive_bytes / 1024.0 / 1024.0
            response_data["network"]["send"] = container_send_bytes / 1024.0 / 1024.0
    elif stats_type == "snapshot":
        ContainerResourceConsumption.objects.create(
            cpu_core = 0,
            cpu_time = 0,
            memory_cap = 0,
            page_fault = 0,
            io_read = 0,
            io_write = 0,
            net_send = 0,
            net_receive = 0,
            net_packets = 0,
        )

    return JsonResponse(response_data)










# Start for Image Controller
def image_index_view(request):
    response_data = {}
    response_data["page_title"] = "Image"
    response_data["module_name"] = "Image"
    response_data["content_name"] = "Index"

    response_data["images"] = Image.objects.all()

    return render(request, "docker_engine/image/index.html", response_data)



def image_detail_view(request, image_name):
    response_data = {}
    response_data["page_title"] = "Image"
    response_data["module_name"] = "Image"
    response_data["content_name"] = image_name

    image_info = docker_client.inspect_image(image=image_name)
    response_data["image"] = {}
    repo_and_tag = image_info["RepoTags"][0]
    response_data["image"]["name"] = repo_and_tag[0:repo_and_tag.find(":")]
    response_data["image"]["tag"] = repo_and_tag[repo_and_tag.find(":")+1:]
    response_data["image"]["id"] = image_info["Id"][7:7+32]
    response_data["image"]["created"] = image_info["Created"]
    response_data["image"]["size"] = round(image_info["Size"]/1024.0/1024.0, 1)

    return render(request, "docker_engine/image/detail.html", response_data)



def image_new_view(request):
    response_data = {}
    response_data["page_title"] = "Image"
    response_data["module_name"] = "Image"
    response_data["content_name"] = "Definition"

    return render(request, "docker_engine/image/new.html", response_data)



def image_delete_view(request, image_name):
    docker_client.remove_image(image_name, force=True)
    Image.objects.get(name=image_name).delete()

    return redirect("/docker/image/index")



def image_pull_view(request):
    repository = request.POST.get("repository")
    if not repository:
        return HttpResponse("Invalid Parameters")

    tag = request.POST.get("tag")
    if not tag:
        tag = "latest"
    for line in docker_client.pull(repository=repository, tag=tag, stream=True):
        print json.dumps(json.loads(line), indent=4)

    usage = check_image_usage(repository)
    Image.objects.create(name=repository, tag=tag, usage=usage)

    return redirect("/docker/image/index")



def image_import_view(request):
    upload_file = request.FILES["import-image"]
    save_file_path = "/tmp/" + upload_file.name
    handle_uploaded_file(upload_file, save_file_path)

    repository = upload_file.name[:upload_file.name.find(".")]
    tag = "latest"
    docker_client.import_image_from_file(filename=save_file_path, repository=repository, tag=tag)

    usage = check_image_usage(repository)
    Image.objects.create(name=repository, tag=tag, usage=usage)

    return redirect("/docker/image/index")



def image_build_view(request):
    handle_uploaded_file(request.FILES["build-image"], "/home/kyle/src/")

    return redirect("/docker/image/index")